home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / gnu_oleo_1_2_2.lha / oleo-1.2.2 / window.c < prev    next >
C/C++ Source or Header  |  1993-03-03  |  31KB  |  1,481 lines

  1. /*    Copyright (C) 1992, 1993 Free Software Foundation, Inc.
  2.  
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7.  
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. GNU General Public License for more details.
  12.  
  13. You should have received a copy of the GNU General Public License
  14. along with this software; see the file COPYING.  If not, write to
  15. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  16.  
  17. #include <stdio.h>
  18. #include "global.h"
  19. #include "window.h"
  20. #include "io-generic.h"
  21. #include "io-abstract.h"
  22. #include "io-utils.h"
  23. #include "io-term.h"
  24. #include "cmd.h"
  25. #include "lists.h"
  26.  
  27. int scr_lines = 24;
  28. int scr_cols = 80;
  29. #define LINES scr_lines
  30. #define COLS scr_cols
  31.  
  32.  
  33. /* These control the layout of input and status lines. */
  34. int user_input = 1;        /* As specified (+/- [0-2]). */
  35. int user_status = 2;
  36. int input = 0;            /* As row address. */
  37. int status = 1;
  38. int input_rows = 1;        /* Size of input and status areas. */
  39. int status_rows = 1;
  40.  
  41. /* These control the layout of edge labels. */
  42. int label_rows;
  43. int label_emcols;
  44.  
  45. /* Window borders: */
  46. int default_right_border = 0;
  47. int default_bottom_border = 0;
  48.  
  49. /* The window list. */
  50. int nwin = 0;
  51. struct window *cwin = 0;
  52. struct window *wins = 0;
  53. static int win_id = 1;
  54.  
  55. int window_after_input = -1;
  56. int input_active = 0;
  57.  
  58.  
  59. /* Low level window operators. */
  60.  
  61. #define MIN_WIN_HEIGHT(W) (W->bottom_edge_r \
  62.                + label_rows * (W->flags & WIN_EDGES ? 2 : 1))
  63.  
  64. #define MIN_WIN_WIDTH(W) (W->right_edge_c \
  65.               + label_emcols * (W->flags & WIN_EDGES ? 6 : 1))
  66. #define MIN_CWIN_HEIGHT  MIN_WIN_HEIGHT(cwin)
  67. #define MIN_CWIN_WIDTH  MIN_WIN_WIDTH(cwin)
  68.  
  69.  
  70. static void 
  71. do_close_window (num)
  72.      int num;
  73. {
  74.   int n;
  75.   struct window *win, *kwin;
  76.   int nlf, nrt, nup, nbl;
  77.   int klo, kho, kld, khd;
  78.   int lo, ho, ld, hd;
  79.   struct tmp
  80.     {
  81.       int l, r, u, b;
  82.     }
  83.    *tmpptr;
  84.  
  85.   if (nwin == 1)
  86.     {
  87.       io_error_msg ("Attempt to delete sole ordinary window.");
  88.       return;
  89.     }
  90.   tmpptr = ck_malloc (sizeof (struct tmp) * nwin);
  91.  
  92.   kwin = &wins[num];
  93.   nlf = nrt = nup = nbl = 0;
  94.   klo = kwin->win_over - kwin->lh_wid;
  95.   kho = kwin->win_over + kwin->numc + kwin->right_edge_c - 1;
  96.   kld = kwin->win_down - (kwin->lh_wid ? label_rows : 0);
  97.   khd = kwin->win_down + kwin->numr + kwin->bottom_edge_r - 1;
  98.  
  99.   for (win = wins; win < &wins[nwin]; win++)
  100.     {
  101.       lo = win->win_over - win->lh_wid;
  102.       ho = win->win_over + win->numc + win->right_edge_c - 1;
  103.       ld = win->win_down - (win->lh_wid ? label_rows : 0);
  104.       hd = win->win_down + win->numr + win->bottom_edge_r - 1;
  105.  
  106.       /* Match to the left ? */
  107.       if (lo == kho + 1)
  108.     {
  109.       if (ld >= kld && hd <= khd)
  110.         tmpptr[nrt++].r = win - wins;
  111.       else if (hd >= kld && ld <= khd)
  112.         nrt = nwin;
  113.     }
  114.       else if (ho == klo - 1)
  115.     {
  116.       if (ld >= kld && hd <= khd)
  117.         tmpptr[nlf++].l = win - wins;
  118.       else if (hd >= kld && ld <= khd)
  119.         nlf = nwin;
  120.     }
  121.       else if (ld == khd + 1)
  122.     {
  123.       if (lo >= klo && ho <= kho)
  124.         tmpptr[nbl++].b = win - wins;
  125.       else if (ho >= kho && lo <= kho)
  126.         nbl = nwin;
  127.     }
  128.       else if (hd == kld - 1)
  129.     {
  130.       if (lo >= klo && ho <= kho)
  131.         tmpptr[nup++].u = win - wins;
  132.       else if (ho >= kho && lo <= kho)
  133.         nup = nwin;
  134.     }
  135.  
  136.     }
  137.   if (nrt == 0)
  138.     nrt = nwin;
  139.   if (nlf == 0)
  140.     nlf = nwin;
  141.   if (nbl == 0)
  142.     nbl = nwin;
  143.   if (nup == 0)
  144.     nup = nwin;
  145.   if (nrt <= nlf && nrt <= nbl && nrt <= nup)
  146.     for (n = 0; n < nrt; n++)
  147.       {
  148.     wins[tmpptr[n].r].numc
  149.       += kwin->lh_wid + kwin->numc + kwin->right_edge_c;
  150.     wins[tmpptr[n].r].win_over
  151.       -= kwin->lh_wid + kwin->numc + kwin->right_edge_c;
  152.       }
  153.   else if (nlf <= nbl && nlf <= nup)
  154.     for (n = 0; n < nlf; n++)
  155.       wins[tmpptr[n].l].numc
  156.     += kwin->lh_wid + kwin->numc + kwin->right_edge_c;
  157.   else if (nbl <= nup)
  158.     for (n = 0; n < nbl; n++)
  159.       {
  160.     wins[tmpptr[n].b].numr
  161.       += kwin->numr + (kwin->lh_wid ? 1 : 0) * label_rows
  162.       + kwin->bottom_edge_r;
  163.  
  164.     wins[tmpptr[n].b].win_down
  165.       -= kwin->numr + (kwin->lh_wid ? 1 : 0) * label_rows
  166.       + kwin->bottom_edge_r;
  167.       }
  168.   else
  169.     for (n = 0; n < nup; n++)
  170.       wins[tmpptr[n].u].numr
  171.     += kwin->numr + (kwin->lh_wid ? 1 : 0) * label_rows;
  172.  
  173.   if (kwin == cwin && kwin != wins)
  174.     --cwin;
  175.   if (cwin == &wins[nwin - 1])
  176.     --cwin;
  177.   while (kwin < &wins[nwin])
  178.     {
  179.       *kwin = kwin[1];
  180.       kwin++;
  181.     }
  182.   --nwin;
  183.   io_recenter_all_win ();
  184.   return;
  185. }
  186.  
  187. static void recenter_axis ();
  188. static void recenter_window ();
  189.  
  190.  
  191. /*
  192.  * RESIZE_SCREEN adjusts the windows list after a screen size change.
  193.  * It presumes that LINES and COLS are the new values.  DR and DC
  194.  * are the changes that just occured to those values.
  195.  */
  196. static void 
  197. resize_screen (dr, dc)
  198.      int dr;
  199.      int dc;
  200. {
  201.   int x, n;
  202.   int lines;
  203.   int firstln;
  204.   int ncols;
  205.   int firstcol;
  206.   int old_lines;
  207.  
  208.   if (!nwin)
  209.     return;
  210.  
  211.   lines = scr_lines - (!!user_status * status_rows) - input_rows;
  212.   old_lines = lines - dr;
  213.   firstln = (user_input > 0) * input_rows + (user_status > 0) * status_rows;
  214.  
  215.   /* First, delete windows that will shrink too much. */
  216.   cwin->curow = curow;
  217.   cwin->cucol = cucol;
  218.   if (dr < 0)
  219.     for (x = 0; x < nwin; x++)
  220.       {
  221.     int rlow =
  222.     (wins[x].win_down - (wins[x].lh_wid ? label_rows : 0) - firstln);
  223.     int rhi = ((wins[x].win_down + wins[x].numr + wins[x].bottom_edge_r)
  224.            - firstln);
  225.     int sqbelow = dr * rlow;
  226.     int sqtohere = dr * rhi;
  227.     sqbelow /= old_lines;
  228.     sqtohere /= old_lines;
  229.     if (wins[x].numr <= sqbelow - sqtohere)
  230.       {
  231.         do_close_window (x);
  232.         x--;
  233.       }
  234.       }
  235.   for (x = 0; x < nwin; ++x)
  236.     {
  237.       int rlow =
  238.       (wins[x].win_down - (wins[x].lh_wid ? label_rows : 0) - firstln);
  239.       int rhi = ((wins[x].win_down + wins[x].numr + wins[x].bottom_edge_r)
  240.          - firstln);
  241.       int sqbelow = dr * rlow;
  242.       int sqtohere = dr * rhi;
  243.       sqbelow /= old_lines;
  244.       sqtohere /= old_lines;
  245.       wins[x].win_down += sqbelow;
  246.       wins[x].numr += sqtohere - sqbelow;
  247.     }
  248.  
  249.   /* then columns */
  250.   firstcol = 1;
  251.   ncols = COLS;
  252.   ncols -= dc;
  253.  
  254.   /* First, delete windows that will shrink too much. */
  255.   if (dc < 0)
  256.     for (x = 0; x < nwin; x++)
  257.       {
  258.     int clow = (wins[x].win_over - wins[x].lh_wid) - firstcol;
  259.     int chi = (wins[x].win_over + wins[x].numc + wins[x].right_edge_c
  260.            - firstcol);
  261.     int sqbelow = dc * clow;
  262.     int sqtohere = dc * chi;
  263.     sqbelow /= ncols;
  264.     sqtohere /= ncols;
  265.     if (wins[x].numc <= sqbelow - sqtohere)
  266.       {
  267.         do_close_window (x);
  268.         x--;
  269.       }
  270.       }
  271.   for (x = 0; x < nwin; ++x)
  272.     {
  273.       int clow = (wins[x].win_over - wins[x].lh_wid) - firstcol;
  274.       int chi = (wins[x].win_over + wins[x].numc + wins[x].right_edge_c
  275.          - firstcol);
  276.       int sqbelow = dc * clow;
  277.       int sqtohere = dc * chi;
  278.       sqbelow /= ncols;
  279.       sqtohere /= ncols;
  280.       wins[x].win_over += sqbelow;
  281.       wins[x].numc += sqtohere - sqbelow;
  282.     }
  283.   for (n = 0; n < nwin; n++)
  284.     recenter_window (&wins[n]);
  285.   io_repaint ();
  286. }
  287.  
  288.  
  289. #if __STDC__
  290. int
  291. win_label_cols (struct window * win, CELLREF hr)
  292. #else
  293. int
  294. win_label_cols (win, hr)
  295.      struct window * win;
  296.      CELLREF hr;
  297. #endif
  298. {
  299.   int lh;
  300.  
  301.   if ((win->flags & WIN_EDGES) == 0)
  302.     lh = 0;
  303. #if BITS_PER_CELLREF>8
  304.   else if ((win->flags & WIN_PAG_HZ) || hr >= 10000)
  305.     lh = 7;
  306.   else if (hr >= 1000)
  307.     lh = 6;
  308.   else if (hr >= 100)
  309.     lh = 5;
  310. #else
  311.   else if ((win->flags & WIN_PAG_HZ) || hr >= 100)
  312.     lh = 5;
  313. #endif
  314.   else if (hr > 10)
  315.     lh = 4;
  316.   else
  317.     lh = 3;
  318.   lh *= label_emcols;
  319.   return lh;
  320. }
  321.  
  322. int
  323. win_label_rows (win)
  324.      struct window * win;
  325. {
  326.   return (win->flags & WIN_EDGES) ? label_rows : 0;
  327. }
  328.  
  329. static void 
  330. set_numcols (win, hr)
  331.      struct window *win;
  332.      CELLREF hr;
  333. {
  334.   int lh = win_label_cols (win, hr);
  335.   win->win_over -= win->lh_wid - lh;
  336.   win->numc += win->lh_wid - lh;
  337.   win->lh_wid = lh;
  338. }
  339.  
  340.  
  341. static void 
  342. page_axis (cur, get, total, loP, hiP)
  343.      CELLREF cur;
  344.      unsigned int (*get) ();
  345.      int total;
  346.      CELLREF *loP, *hiP;
  347. {
  348.   CELLREF lo, hi;
  349.   unsigned int w, ww;
  350.  
  351.   lo = hi = MIN_ROW;
  352.   w = (*get) (hi);
  353.   for (;;)
  354.     {
  355.       ww = (*get) (hi + 1);
  356.       while (w + ww <= total && hi < MAX_ROW)
  357.     {
  358.       hi++;
  359.       w += ww;
  360.       ww = (*get) (hi + 1);
  361.     }
  362.       if (hi >= cur)
  363.     break;
  364.       hi++;
  365.       lo = hi;
  366.       w = ww;
  367.     }
  368.   if (lo > cur || hi > MAX_ROW)
  369.     io_error_msg ("Can't find a non-zero-sized cell page_axis");
  370.   *loP = lo;
  371.   *hiP = hi;
  372. }
  373.  
  374.  
  375. static void 
  376. recenter_axis (cur, get, total, loP, hiP)
  377.      CELLREF cur;
  378.      unsigned int (*get) ();
  379.      int total;
  380.      CELLREF *loP, *hiP;
  381. {
  382.   CELLREF lo, hi;
  383.   unsigned int tot;
  384.   int n;
  385.   int more;
  386.  
  387.   lo = hi = cur;
  388.   n = tot = (*get) (cur);
  389.   do
  390.     {
  391.       if (lo > MIN_ROW && tot + (n = (*get) (lo - 1)) <= total)
  392.     {
  393.       --lo;
  394.       tot += n;
  395.       more = 1;
  396.     }
  397.       else
  398.     more = 0;
  399.       if (hi < MAX_ROW && tot + (n = (*get) (hi + 1)) <= total)
  400.     {
  401.       hi++;
  402.       tot += n;
  403.       more++;
  404.     }
  405.     }
  406.   while (more);
  407.   *loP = lo;
  408.   *hiP = hi;
  409. }
  410.  
  411. static void 
  412. recenter_window (win)
  413.      struct window *win;
  414. {
  415.   if (win->flags & WIN_PAG_VT)
  416.     page_axis (win->curow, get_scaled_height, win->numr,
  417.            &(win->screen.lr), &(win->screen.hr));
  418.   else
  419.     recenter_axis (win->curow, get_scaled_height, win->numr,
  420.            &(win->screen.lr), &(win->screen.hr));
  421.   set_numcols (win, win->screen.hr);
  422.   if (win->flags & WIN_PAG_HZ)
  423.     page_axis (win->cucol, get_scaled_width, win->numc,
  424.            &(win->screen.lc), &(win->screen.hc));
  425.   else
  426.     recenter_axis (win->cucol, get_scaled_width, win->numc,
  427.            &(win->screen.lc), &(win->screen.hc));
  428. }
  429.  
  430.  
  431. static void
  432. shift_linked_window (dn, ov)
  433.      long dn;
  434.      long ov;
  435. {
  436.   struct window *win;
  437.  
  438.   win = cwin;
  439.   while (win->link != -1)
  440.     {
  441.       win = &wins[win->link];
  442.       if (win == cwin)        /* Loop check! */
  443.     return;
  444.       if ((win->flags & WIN_LCK_VT) == 0)
  445.     win->curow += dn;
  446.       if ((win->flags & WIN_LCK_HZ) == 0)
  447.     win->cucol += ov;
  448.       if (win->curow < win->screen.lr || win->curow > win->screen.hr
  449.       || win->cucol < win->screen.lc || win->cucol > win->screen.hc)
  450.     recenter_window (win);
  451.     }
  452. }
  453.  
  454.  
  455. static void 
  456. find_nonzero (curp, lo, hi, get)
  457.      CELLREF *curp;
  458.      CELLREF lo;
  459.      CELLREF hi;
  460.      unsigned int (*get) ();
  461. {
  462.   CELLREF cc;
  463.   unsigned int n;
  464.  
  465.   cc = *curp;
  466.  
  467.   if (cc < hi)
  468.     {
  469.       cc++;
  470.       while ((n = (*get) (cc)) == 0)
  471.     {
  472.       if (cc == hi)
  473.         break;
  474.       cc++;
  475.     }
  476.       if (n)
  477.     {
  478.       *curp = cc;
  479.       return;
  480.     }
  481.     }
  482.   if (cc > lo)
  483.     {
  484.       --cc;
  485.       while ((n = (*get) (cc)) == 0)
  486.     {
  487.       if (cc == lo)
  488.         break;
  489.       --cc;
  490.     }
  491.       if (n)
  492.     {
  493.       *curp = cc;
  494.       return;
  495.     }
  496.     }
  497. }
  498.  
  499. static int 
  500. scroll_axis (cur, over, total, get, ret1, ret2, offp)
  501.      CELLREF cur;
  502.      int over;
  503.      int total;
  504.      unsigned int (*get) ();
  505.      CELLREF *ret1;
  506.      CELLREF *ret2;
  507.      int *offp;
  508. {
  509.   unsigned int tot; 
  510.  
  511.   int inc;
  512.   CELLREF fini;
  513.   int num;
  514.   CELLREF p1, p2;
  515.   int n;
  516.  
  517.   inc = (over > 0 ? 1 : -1);
  518.   fini = over > 0 ? MAX_ROW : MIN_ROW;
  519.   num = over > 0 ? over : -over;
  520.  
  521.   if (inc > 0 ? *ret2 == MAX_ROW : *ret1 == MIN_ROW)
  522.     return 1;
  523.   p1 = inc > 0 ? *ret2 + 1 : *ret1 - 1;
  524.   p2 = p1;
  525.   for (;;)
  526.     {
  527.       --num;
  528.       tot = (*get) (p1);
  529.       while (p2 != fini && tot + (n = (*get) (p2 + inc)) <= total)
  530.     {
  531.       p2 += inc;
  532.       tot += n;
  533.     }
  534.       if (!num || p2 == fini)
  535.     break;
  536.     }
  537.   if (num)
  538.     return 1;
  539.   while (tot + (n = (*get) (p1 - inc)) <= total)
  540.     {
  541.       p1 -= inc;
  542.       tot += n;
  543.       if (inc > 0)
  544.     (*offp)++;
  545.     }
  546.   if (p1 > p2)
  547.     {
  548.       *ret1 = p2;
  549.       *ret2 = p1;
  550.     }
  551.   else
  552.     {
  553.       *ret1 = p1;
  554.       *ret2 = p2;
  555.     }
  556.   return 0;
  557. }
  558.  
  559. static int 
  560. page_scroll_axis (cur, over, total, get, ret1, ret2, offp)
  561.      CELLREF cur;
  562.      int over;
  563.      int total;
  564.      unsigned int (*get) ();
  565.      CELLREF *ret1;
  566.      CELLREF *ret2;
  567.      int *offp;
  568. {
  569.   int n_over;
  570.   CELLREF lo, hi;
  571.   int tot;
  572.   int ww;
  573.  
  574.   n_over = 0;
  575.   lo = hi = MIN_ROW;
  576.   tot = (*get) (hi);
  577.   for (;;)
  578.     {
  579.       while (hi < MAX_ROW && tot + (ww = (*get) (hi + 1)) <= total)
  580.     {
  581.       hi++;
  582.       tot += ww;
  583.     }
  584.       if (hi >= cur)
  585.     break;
  586.       hi++;
  587.       n_over++;
  588.       lo = hi;
  589.       tot = ww;
  590.     }
  591.   n_over += over;
  592.   if (n_over < 0)
  593.     return 1;
  594.  
  595.   lo = hi = MIN_ROW;
  596.   tot = (*get) (hi);
  597.   for (;;)
  598.     {
  599.       while (hi < MAX_ROW && tot + (ww = (*get) (hi + 1)) <= total)
  600.     {
  601.       hi++;
  602.       tot += ww;
  603.     }
  604.       if (!n_over || hi == MAX_ROW)
  605.     break;
  606.       --n_over;
  607.       hi++;
  608.       lo = hi;
  609.       tot = ww;
  610.     }
  611.   if (hi == MAX_ROW && n_over)
  612.     return 1;
  613.   *ret1 = lo;
  614.   *ret2 = hi;
  615.   return 0;
  616. }
  617.  
  618.  
  619.  
  620. /* External window interface */
  621.  
  622. void 
  623. io_set_label_size (r, c)
  624.      int r;
  625.      int c;
  626. {
  627.   /* fixme */
  628. }
  629.  
  630. void 
  631. io_set_scr_size (lines, cols)
  632.      int lines;
  633.      int cols;
  634. {
  635.   int dl = lines - scr_lines;
  636.   int dc = cols - scr_cols;
  637.  
  638.   scr_lines = lines;
  639.   scr_cols = cols;
  640.  
  641.   resize_screen (dl, dc);
  642. }
  643.  
  644. void 
  645. io_set_input_rows (n)
  646.      int n;
  647. {
  648.   input_rows = n;
  649.   io_set_input_status (user_input, user_status, 1);
  650. }
  651.  
  652. void 
  653. io_set_status_rows (n)
  654.      int n;
  655. {
  656.   status_rows = n;
  657.   io_set_input_status (user_input, user_status, 1);
  658. }
  659.  
  660. void 
  661. io_set_input_status (inp, stat, redraw)
  662.      int inp;
  663.      int stat;
  664.      int redraw;
  665. {
  666.   int inpv = inp < 0 ? -inp : inp;
  667.   int inpsgn = inp == inpv ? 1 : -1;
  668.   int statv = stat < 0 ? -stat : stat;
  669.   int statsgn = stat == statv ? 1 : -1;
  670.   int new_ui;
  671.   int new_us;
  672.   int new_inp;
  673.   int new_stat;
  674.  
  675.   if (inpv == 0 || inpv > 2)
  676.     io_error_msg ("Bad input location %d; it should be +/- 1, or 2", inp);
  677.   else if (statv > 2)
  678.     io_error_msg ("Bad status location %d; it should be +/- 0, 1, or 2",
  679.           inp);
  680.   else
  681.     {
  682.       new_ui = inp;
  683.       new_us = stat;
  684.       if (inpsgn != statsgn)
  685.     if (inpsgn > 0)
  686.       {
  687.         new_inp = 0;
  688.         new_stat = LINES - status_rows;
  689.       }
  690.     else
  691.       {
  692.         new_inp = LINES - input_rows;
  693.         new_stat = 0;
  694.       }
  695.       else
  696.     {
  697.       if (inpv > statv)
  698.         {
  699.           new_inp = user_status ? status_rows : 0;
  700.           new_stat = 0;
  701.         }
  702.       else
  703.         {
  704.           new_inp = 0;
  705.           new_stat = input_rows;
  706.         }
  707.       if (inpsgn < 0)
  708.         {
  709.           new_stat = LINES - status - status_rows;
  710.           new_inp = LINES - input - input_rows;
  711.         }
  712.     }
  713.       if (redraw)
  714.     {
  715.       int vchange =
  716.       (((new_ui > 0 ? input_rows : 0)
  717.         + (new_us > 0 ? status_rows : 0))
  718.        - ((user_input > 0 ? input_rows : 0)
  719.           + (user_status > 0 ? status_rows : 0)));
  720.       int grow = (user_status
  721.               ? (new_us ? 0 : status_rows)
  722.               : (new_us ? -status_rows : 0));
  723.       int cell_top =
  724.       ((user_status > 0 ? status_rows : 0)
  725.        + (user_input > 0 ? input_rows : 0));
  726.  
  727.       if (grow < 0)
  728.         {
  729.           int x;
  730.         re:
  731.           for (x = 0; x < nwin; ++x)
  732.         {
  733.           int top = wins[x].win_down - win_label_rows(&wins[x]);
  734.           if (cell_top == top && (wins[x].numr <= -grow))
  735.             {
  736.               do_close_window (x);
  737.               goto re;
  738.             }
  739.         }
  740.         }
  741.  
  742.       if (grow)
  743.         {
  744.           int x;
  745.           for (x = 0; x < nwin; ++x)
  746.         {
  747.           int top =
  748.           wins[x].win_down - win_label_rows (&wins[x]);
  749.           if (cell_top == top)
  750.             wins[x].numr += vchange;
  751.         }
  752.         }
  753.       if (vchange)
  754.         {
  755.           int x;
  756.           for (x = 0; x < nwin; ++x)
  757.         wins[x].win_down += vchange;
  758.         }
  759.       io_repaint ();
  760.     }
  761.       user_input = new_ui;
  762.       user_status = new_us;
  763.       input = new_inp;
  764.       status = new_stat;
  765.     }
  766. }
  767.  
  768. void 
  769. io_set_cwin (win)
  770.      struct window *win;
  771. {
  772.   io_hide_cell_cursor ();
  773.   cwin->curow = curow;
  774.   cwin->cucol = cucol;
  775.   cwin = win;
  776.   curow = cwin->curow;
  777.   cucol = cwin->cucol;
  778.   io_display_cell_cursor ();
  779. }
  780.  
  781.  
  782. #if __STDC__
  783. void 
  784. io_pr_cell (CELLREF r, CELLREF c, CELL *cp)
  785. #else
  786. void 
  787. io_pr_cell (r, c, cp)
  788.      CELLREF r;
  789.      CELLREF c;
  790.      CELL *cp;
  791. #endif
  792. {
  793.   struct window *win;
  794.  
  795.   for (win = wins; win < &wins[nwin]; win++)
  796.     {
  797.       if (r < win->screen.lr || r > win->screen.hr
  798.       || c < win->screen.lc || c > win->screen.hc)
  799.     continue;
  800.       io_pr_cell_win (win, r, c, cp);
  801.     }
  802. }
  803.  
  804. void
  805. io_redo_region (rng)
  806.      struct rng * rng;
  807. {
  808.   CELL * cp;
  809.   CELLREF r, c;
  810.   find_cells_in_range (rng);
  811.   cp = next_row_col_in_range (&r, &c);
  812.   while (cp)
  813.     {
  814.       io_pr_cell (r, c, cp);
  815.       cp = next_row_col_in_range (&r, &c);
  816.     }
  817. }
  818.  
  819. /* Create a new window by splitting the current one. */
  820. void 
  821. io_win_open (hv, where)
  822.      int hv;
  823.      int where;
  824. {
  825.   int tmp;
  826.   struct window *win;
  827.  
  828.   if (   (!hv
  829.       && (where < MIN_CWIN_WIDTH
  830.           || (cwin->numc + cwin->lh_wid + cwin->right_edge_c - where
  831.                < MIN_CWIN_WIDTH)))
  832.       || (hv
  833.       && (where < MIN_CWIN_HEIGHT
  834.           || (cwin->numr + cwin->bottom_edge_r
  835.           + (cwin->lh_wid ? label_rows : 0) - where
  836.           < MIN_CWIN_HEIGHT))))
  837.     {
  838.       io_error_msg ("Window won't fit!");
  839.       return;
  840.     }
  841.  
  842.   nwin++;
  843.   tmp = cwin - wins;
  844.   wins = ck_realloc (wins, nwin * sizeof (struct window));
  845.   win = &wins[nwin - 1];
  846.   cwin = &wins[tmp];
  847.   win->id = win_id++;
  848.   win->bottom_edge_r = cwin->bottom_edge_r;
  849.   win->right_edge_c = cwin->right_edge_c;
  850.   /* set_numcols will take care of fixing win_over if edges are on. */
  851.   win->win_over = cwin->win_over + (hv ? 0 : where) - cwin->lh_wid;
  852.   win->win_down = cwin->win_down + (hv ? where : 0);
  853.   win->flags = cwin->flags;
  854.   win->link = -1;
  855.   win->lh_wid = 0;
  856.   win->win_slops = 0;
  857.   win->numc = cwin->numc + cwin->lh_wid + (hv ? 0 : -where);
  858.   win->numr = cwin->numr + (hv ? -where : 0);
  859.   win->curow = curow;
  860.   win->cucol = cucol;
  861.   set_numcols (win, curow);
  862.   cwin->numc -= (hv ? 0 : win->numc + win->lh_wid + win->right_edge_c);
  863.   cwin->numr -=
  864.     (hv ? win->numr + (win->lh_wid ? label_rows : 0) + win->bottom_edge_r
  865.      : 0);
  866.   cwin->curow = curow;
  867.   cwin->cucol = cucol;
  868.   io_hide_cell_cursor ();
  869.   win = cwin;
  870.   cwin = &wins[nwin - 1];
  871.   recenter_window (cwin);
  872.   recenter_window (win);
  873.   io_display_cell_cursor ();
  874.   io_repaint ();
  875. }
  876.  
  877. void 
  878. io_win_close (win)
  879.      struct window *win;
  880. {
  881.   do_close_window (win - wins);
  882. }
  883.  
  884. #if __STDC__
  885. void 
  886. io_move_cell_cursor (CELLREF rr, CELLREF cc)
  887. #else
  888. void 
  889. io_move_cell_cursor (rr, cc)
  890.      CELLREF rr;
  891.      CELLREF cc;
  892. #endif
  893. {
  894.   if (cwin->link != -1)
  895.     shift_linked_window ((long) rr - curow, (long) cc - cucol);
  896.   if (rr < cwin->screen.lr || rr > cwin->screen.hr
  897.       || cc < cwin->screen.lc || cc > cwin->screen.hc)
  898.     {
  899.       cwin->curow = curow = rr;
  900.       cwin->cucol = cucol = cc;
  901.       recenter_window (cwin);
  902.       io_repaint_win (cwin);
  903.       if (cwin->link > 0)
  904.     io_repaint_win (&wins[cwin->link]);
  905.     }
  906.   else
  907.     {
  908.       io_hide_cell_cursor ();
  909.       curow = rr;
  910.       cucol = cc;
  911.       io_display_cell_cursor ();
  912.       io_update_status ();
  913.     }
  914.   if (get_scaled_width (cucol) == 0)
  915.     find_nonzero (&cucol, cwin->screen.lc, cwin->screen.hc, get_scaled_width);
  916.   if (get_scaled_height (curow) == 0)
  917.     find_nonzero (&curow, cwin->screen.lr, cwin->screen.hr, get_scaled_height);
  918. }
  919.  
  920. void 
  921. io_shift_cell_cursor (dirn)
  922.      int dirn;
  923. {
  924.   CELLREF c;
  925.   CELLREF r;
  926.   int w = 0;
  927.   int over, down;
  928.  
  929.   over = colmagic[dirn] * how_many;
  930.   down = rowmagic[dirn] * how_many;
  931.   if (over > 0)
  932.     {
  933.       c = cucol;
  934.       while (c < MAX_COL && over-- > 0)
  935.     {
  936.       c++;
  937.       while ((w = get_scaled_width (c)) == 0 && c < MAX_COL)
  938.         c++;
  939.     }
  940.       if (over > 0 || c == cucol || w == 0)
  941.     {
  942.       io_error_msg ("Can't go right");
  943.       return;
  944.     }
  945.     }
  946.   else if (over < 0)
  947.     {
  948.       c = cucol;
  949.       while (c > MIN_COL && over++ < 0)
  950.     {
  951.       --c;
  952.       while ((w = get_scaled_width (c)) == 0 && c > MIN_COL)
  953.         --c;
  954.     }
  955.       if (over < 0 || c == cucol || w == 0)
  956.     {
  957.       io_error_msg ("Can't go left");
  958.       return;
  959.     }
  960.     }
  961.   else
  962.     c = cucol;
  963.  
  964.   if (down > 0)
  965.     {
  966.       r = curow;
  967.       while (r < MAX_ROW && down-- > 0)
  968.     {
  969.       r++;
  970.       while ((w = get_scaled_height (r)) == 0 && r < MAX_ROW)
  971.         r++;
  972.     }
  973.       if (down > 0 || r == curow || w == 0)
  974.     {
  975.       io_error_msg ("Can't go down");
  976.       return;
  977.     }
  978.     }
  979.   else if (down < 0)
  980.     {
  981.       r = curow;
  982.       while (r > MIN_ROW && down++ < 0)
  983.     {
  984.       --r;
  985.       while ((w = get_scaled_height (r)) == 0 && r > MIN_ROW)
  986.         --r;
  987.     }
  988.       if (down < 0 || r == curow || w == 0)
  989.     {
  990.       io_error_msg ("Can't go up");
  991.       return;
  992.     }
  993.     }
  994.   else
  995.     r = curow;
  996.  
  997.   io_move_cell_cursor (r, c);
  998. }
  999.  
  1000. void 
  1001. io_scroll_cell_cursor (magic)
  1002.      int magic;
  1003. {
  1004.   int off_dn, off_rt;
  1005.  
  1006.   struct rng s;
  1007.   CELLREF cr, cc;
  1008.   int over, down;
  1009.   int ret;
  1010.  
  1011.   over = colmagic[magic];
  1012.   down = rowmagic[magic];
  1013.  
  1014.   s.lr = cwin->screen.lr;
  1015.   s.hr = cwin->screen.hr;
  1016.   if (down)
  1017.     {
  1018.       off_dn = curow - cwin->screen.lr;
  1019.       if (cwin->flags & WIN_PAG_VT)
  1020.     ret = page_scroll_axis
  1021.       (curow, down, cwin->numr, get_scaled_height, &(s.lr), &(s.hr), &off_dn);
  1022.       else
  1023.     ret = scroll_axis
  1024.       (curow, down, cwin->numr, get_scaled_height, &(s.lr), &(s.hr), &off_dn);
  1025.       cr = (off_dn > s.hr - s.lr) ? s.hr : s.lr + off_dn;
  1026.       if (ret)
  1027.     io_error_msg ("Can't scroll that far");
  1028.       set_numcols (cwin, s.hr);
  1029.     }
  1030.   else
  1031.     cr = curow;
  1032.  
  1033.   off_rt = cucol - cwin->screen.lc;
  1034.  
  1035.   s.lc = cwin->screen.lc;
  1036.   s.hc = cwin->screen.hc;
  1037.   if (over)
  1038.     {
  1039.       if (cwin->flags & WIN_PAG_HZ)
  1040.     ret = page_scroll_axis
  1041.       (cucol, over, cwin->numc, get_scaled_width, &(s.lc), &(s.hc), &off_rt);
  1042.       else
  1043.     ret = scroll_axis (cucol, over, cwin->numc, get_scaled_width, &(s.lc), &(s.hc), &off_rt);
  1044.       if (ret)
  1045.     io_error_msg ("Can't scroll that far");
  1046.       cc = (s.hc - s.lc < off_rt) ? s.hc : s.lc + off_rt;
  1047.     }
  1048.   else if ((cwin->flags & WIN_PAG_HZ) == 0)
  1049.     /* ... */
  1050.     cc = cucol;
  1051.   else
  1052.     cc = cucol;
  1053.  
  1054.   /*fixme The original has a big #if 0 here. */
  1055.   if (cwin->link != -1)
  1056.     shift_linked_window ((long) cr - curow, (long) cc - cucol);
  1057.  
  1058.   cwin->screen = s;
  1059.   curow = cr;
  1060.   cucol = cc;
  1061.  
  1062.   if (get_scaled_width (cucol) == 0)
  1063.     find_nonzero (&cucol, cwin->screen.lc, cwin->screen.hc, get_scaled_width);
  1064.   if (get_scaled_height (curow) == 0)
  1065.     find_nonzero (&curow, cwin->screen.lr, cwin->screen.hr, get_scaled_height);
  1066.  
  1067.   io_repaint_win (cwin);
  1068.   if (cwin->link > 0)
  1069.     io_repaint_win (&wins[cwin->link]);
  1070. }
  1071.  
  1072. void 
  1073. io_recenter_cur_win ()
  1074. {
  1075.   cwin->curow = curow;
  1076.   cwin->cucol = cucol;
  1077.   recenter_window (cwin);
  1078.   io_repaint_win (cwin);
  1079.   if (cwin->link > 0)
  1080.     io_repaint_win (&wins[cwin->link]);
  1081. }
  1082.  
  1083. void 
  1084. io_recenter_all_win ()
  1085. {
  1086.   int n;
  1087.   if (!nwin)
  1088.     return;
  1089.   cwin->curow = curow;
  1090.   cwin->cucol = cucol;
  1091.   for (n = 0; n < nwin; n++)
  1092.     recenter_window (&wins[n]);
  1093.   io_repaint ();
  1094. }
  1095.  
  1096. void 
  1097. io_set_win_flags (w, f)
  1098.      struct window *w;
  1099.      int f;
  1100. {
  1101.   if ((f & WIN_EDGES) && !(w->flags & WIN_EDGES))
  1102.     {
  1103.       if (w->numr < 2 || w->numc < 6)
  1104.     io_error_msg ("Edges wouldn't fit!");
  1105.       w->win_down++;
  1106.       w->numr--;
  1107.       set_numcols (w, w->screen.hr);
  1108.     }
  1109.   else if (!(f & WIN_EDGES) && (w->flags & WIN_EDGES))
  1110.     {
  1111.       w->win_over -= w->lh_wid;
  1112.       w->numc += w->lh_wid;
  1113.       w->lh_wid = 0;
  1114.       w->win_down--;
  1115.       w->numr++;
  1116.     }
  1117.   w->flags = f;
  1118. }
  1119.  
  1120. #ifdef __STDC__
  1121. void 
  1122. io_write_window_config (struct line * out)
  1123. #else
  1124. void 
  1125. io_write_window_config (out)
  1126.      struct line *out;
  1127. #endif
  1128. {
  1129.   int n;
  1130.   char buf[90];
  1131.   struct line scratch;
  1132.   scratch.alloc = 0;
  1133.   scratch.buf = 0;
  1134.  
  1135.   cwin->curow = curow;
  1136.   cwin->cucol = cucol;
  1137.   sprint_line (out, "O;status %d\n", user_status);
  1138.   if (nwin > 1)
  1139.     {
  1140.       /* ... *//* fixme ? */
  1141.     }
  1142.   for (n = 0; n < nwin; n++)
  1143.     {
  1144.       buf[0] = '\0';
  1145.       if (wins[n].flags & WIN_LCK_HZ)
  1146.     strcat (buf, ",lockh");
  1147.       if (wins[n].flags & WIN_LCK_VT)
  1148.     strcat (buf, ",lockv");
  1149.       if (wins[n].flags & WIN_PAG_HZ)
  1150.     strcat (buf, ",pageh");
  1151.       if (wins[n].flags & WIN_PAG_VT)
  1152.     strcat (buf, ",pagev");
  1153.       if (wins[n].flags & WIN_EDGE_REV)
  1154.     strcat (buf, ",standout");
  1155.       if ((wins[n].flags & WIN_EDGES) == 0)
  1156.     strcat (buf, ",noedges");
  1157.       scratch = *out;
  1158.       out->alloc = 0;
  1159.       out->buf = 0;
  1160.       sprint_line (out, "%sW;N%d;A%u %u;C%d %d %d;O%s\n",
  1161.            scratch.buf, n + 1, wins[n].curow, wins[n].cucol, 7, 0, 7,
  1162.            buf + 1);
  1163.       free (scratch.buf);
  1164.     }
  1165. }
  1166.  
  1167. #ifdef __STDC__
  1168. void 
  1169. io_read_window_config (char * line)
  1170. #else
  1171. void 
  1172. io_read_window_config (line)
  1173.      char *line;
  1174. #endif
  1175. {
  1176.   int wnum = 0;
  1177.   char *text;
  1178.   CELLREF nrow = NON_ROW, ncol = NON_COL;
  1179.   char *split = 0;
  1180.   char *opts = 0;
  1181.   struct window *win;
  1182.  
  1183.   text = line;
  1184.   for (;;)
  1185.     {
  1186.       switch (*text++)
  1187.     {
  1188.       /* Window Number */
  1189.     case 'N':
  1190.       wnum = astol (&text);
  1191.       break;
  1192.       /* Cursor At */
  1193.     case 'A':
  1194.       nrow = astol (&text);
  1195.       ncol = astol (&text);
  1196.       break;
  1197.       /* JF: Window options */
  1198.     case 'O':
  1199.       opts = text;
  1200.       while (*text && *text != ';')
  1201.         text++;
  1202.       break;
  1203.       /* Split into two windows */
  1204.     case 'S':
  1205.       split = text;
  1206.       while (*text && *text != ';')
  1207.         text++;
  1208.       break;
  1209.       /* Set Colors NOT supported */
  1210.     case 'C':
  1211.       while (*text && *text != ';')
  1212.         text++;
  1213.       break;
  1214.       /* Alternate border NOT supported. . . */
  1215.     case 'B':
  1216.       break;
  1217.     default:
  1218.       --text;
  1219.       break;
  1220.     }
  1221.       if (*text == '\0' || *text == '\n')
  1222.     break;
  1223.       if (*text != ';')
  1224.     {
  1225.       char *bad;
  1226.  
  1227.       bad = text;
  1228.       while (*text && *text != ';')
  1229.         text++;
  1230.       if (*text)
  1231.         *text++ = '\0';
  1232.       io_error_msg ("Unknown SYLK window cmd: %s", bad);
  1233.       if (!*text)
  1234.         break;
  1235.     }
  1236.       else
  1237.     *text++ = '\0';
  1238.     }
  1239.   if (wnum < 1 || wnum > nwin)
  1240.     {
  1241.       io_error_msg ("Window %d out of range in SYLK line %s", wnum, line);
  1242.       return;
  1243.     }
  1244.   --wnum;
  1245.   win = &wins[wnum];
  1246.   if (nrow != NON_ROW)
  1247.     {
  1248.       win->curow = nrow;
  1249.       win->cucol = ncol;
  1250.       if (win == cwin)
  1251.     {
  1252.       curow = nrow;
  1253.       cucol = ncol;
  1254.     }
  1255.       recenter_window (win);
  1256.     }
  1257.   if (split)
  1258.     {
  1259.       int hv = 0;
  1260.       int where;
  1261.       int link;
  1262.       struct window *new;
  1263.  
  1264.       switch (*split++)
  1265.     {
  1266.     case 'H':
  1267.     case 'h':
  1268.       hv = 1;
  1269.       break;
  1270.     case 'v':
  1271.     case 'V':
  1272.       hv = 0;
  1273.       break;
  1274.     case 't':
  1275.     case 'T':
  1276.       io_error_msg ("Window split titles not supported");
  1277.       return;
  1278.     default:
  1279.       break;
  1280.     }
  1281.       if (*split == 'L')
  1282.     {
  1283.       link = wnum;
  1284.       split++;
  1285.     }
  1286.       else
  1287.     link = -1;
  1288.  
  1289.       where = astol (&split);
  1290.  
  1291.       if (hv ? where >= win->numr : where >= win->numc)
  1292.     io_error_msg ("Can't split window: screen too small");
  1293.  
  1294.       nwin++;
  1295.       wins = ck_realloc (wins, nwin * sizeof (struct window));
  1296.       cwin = wins;
  1297.       win = &wins[wnum];
  1298.       new = &wins[nwin - 1];
  1299.  
  1300.       win->numc -= (hv ? 0 : where);
  1301.       win->numr -= (hv ? where : 0);
  1302.       win->curow = curow;
  1303.       win->cucol = cucol;
  1304.  
  1305.       new->flags = WIN_EDGES | WIN_EDGE_REV;    /* Mplan defaults */
  1306.       new->lh_wid = 0;        /* For now */
  1307.       new->link = link;
  1308.  
  1309.       new->win_over = win->win_over + (hv ? -win->lh_wid : win->numc);
  1310.       new->win_down = win->win_down + (hv ? win->numr + 1 : 0);
  1311.       new->numc = (hv ? win->numc + win->lh_wid : where);
  1312.       new->numr = (hv ? where - 1 : win->numr);
  1313.       new->curow = curow;
  1314.       new->cucol = cucol;
  1315.       set_numcols (new, curow);
  1316.       recenter_window (win);
  1317.       recenter_window (new);
  1318.     }
  1319.   if (opts)
  1320.     {
  1321.       char *np;
  1322.       while (np =(char *) index (opts, ','))
  1323.     {
  1324.       *np = '\0';
  1325.       set_options (opts);
  1326.       *np++ = ';';
  1327.       opts = np;
  1328.     }
  1329.       if (np = (char *)rindex (opts, '\n'))
  1330.     *np = '\0';
  1331.       set_options (opts);
  1332.     }
  1333. }
  1334.  
  1335.  
  1336.  
  1337. static struct mouse_event *current_mouse;
  1338. static struct mouse_event *free_mouse;
  1339. static int mouse_id = 0;
  1340.  
  1341. static void 
  1342. init_mouse ()
  1343. {
  1344.   current_mouse = free_mouse =
  1345.   (struct mouse_event *) ck_malloc (sizeof (struct mouse_event));
  1346.   free_mouse->next = free_mouse;
  1347.   free_mouse->prev = free_mouse;
  1348. }
  1349.  
  1350. static int mouse_location ();
  1351.  
  1352. int 
  1353. enqueue_mouse_event (r, c, button, downp)
  1354.      int r;
  1355.      int c;
  1356.      int button;
  1357.      int downp;
  1358. {
  1359.   struct mouse_event *m = free_mouse;
  1360.   if (m->next == current_mouse)
  1361.     {
  1362.       m->next =
  1363.     (struct mouse_event *) ck_malloc (sizeof (struct mouse_event));
  1364.       m->next->prev = m;
  1365.       m->next->next = current_mouse;
  1366.       current_mouse->prev = m->next;
  1367.       m->seq = mouse_id++;
  1368.       if (m->seq > 255)
  1369.     panic ("Too many mouse events enqueued.");
  1370.     }
  1371.   free_mouse = m->next;
  1372.   m->row = r;
  1373.   m->col = c;
  1374.   m->button = button;
  1375.   m->downp = downp;
  1376.   m->location = mouse_location (&m->r, &m->c, m);
  1377.   return m->seq;
  1378. }
  1379.  
  1380. void 
  1381. dequeue_mouse_event (out, seq)
  1382.      struct mouse_event *out;
  1383.      int seq;
  1384. {
  1385.   free_mouse->seq = seq;
  1386.   while (current_mouse->seq != seq)
  1387.     current_mouse = current_mouse->next;
  1388.   if (current_mouse == free_mouse)
  1389.     {
  1390.       out->seq = seq;
  1391.       out->button = MOUSE_QERROR;
  1392.       return;
  1393.     }
  1394.   *out = *current_mouse;
  1395.   out->next = out->prev = 0;
  1396.   current_mouse = current_mouse->next;
  1397. }
  1398.  
  1399.  
  1400.  
  1401. #ifdef __STDC__
  1402. void 
  1403. io_init_windows (int sl, int sc, int ui, int us, int ir, int sr,
  1404.          int lr, int lc) 
  1405. #else
  1406. void 
  1407. io_init_windows (sl, sc, ui, us, ir, sr, lr, lc)
  1408.      int sl, sc;
  1409.      int ui, us;
  1410.      int ir, sr;
  1411.      int lr, lc;
  1412. #endif
  1413. {
  1414.   print_width = 80;        /* default ascii print width */
  1415.   scr_lines = sl;
  1416.   scr_cols = sc;
  1417.   input_rows = ir;
  1418.   status_rows = sr;
  1419.   label_rows = lr;
  1420.   label_emcols = lc;
  1421.   io_set_input_status (ui, us, 0);
  1422.   nwin = 1;
  1423.   wins = cwin = ck_malloc (sizeof (struct window));
  1424.   wins->id = win_id++;
  1425.   wins->win_over = 0;        /* This will be fixed by a future set_numcols */
  1426.   wins->win_down = (label_rows
  1427.             + (user_status > 0) * status_rows
  1428.             + (user_input > 0) * input_rows);
  1429.   wins->flags = WIN_EDGES | WIN_EDGE_REV;
  1430.   wins->numr = (scr_lines - label_rows - !!user_status * status_rows
  1431.         - input_rows - default_bottom_border);
  1432.   wins->numc = scr_cols - default_right_border;
  1433.   wins->bottom_edge_r = default_bottom_border;
  1434.   wins->right_edge_c = default_right_border;
  1435.   wins->link = -1;
  1436.   wins->lh_wid = 0;
  1437.   curow = wins->curow = MIN_ROW;
  1438.   cucol = wins->cucol = MIN_COL;
  1439.   wins->win_slops = 0;
  1440.   init_mouse ();
  1441. }
  1442.  
  1443. static int 
  1444. mouse_location (cr, cc, ev)
  1445.      CELLREF *cr;
  1446.      CELLREF *cc;
  1447.      struct mouse_event *ev;
  1448. {
  1449.   int n;
  1450.   if (ev->row >= input && ev->row <= input + input_rows)
  1451.     return MOUSE_ON_INPUT;
  1452.   if (user_status && ev->row >= status
  1453.       && ev->row <= status + status_rows)
  1454.     return MOUSE_ON_STATUS;
  1455.   for (n = 0; n < nwin; ++n)
  1456.     {
  1457.       struct window *w = &wins[n];
  1458.       if (ev->row >= w->win_down
  1459.       && ev->row < w->win_down + w->numr
  1460.       && ev->col < w->win_over + w->numc
  1461.       && ev->col >= w->win_over)
  1462.     {
  1463.       int row_off = ev->row - w->win_down;
  1464.       int col_off = ev->col - w->win_over;
  1465.       int rh = 0;
  1466.       int cw = 0;
  1467.       CELLREF c, r;
  1468.       for (c = w->screen.lc; c <= w->screen.hc; ++c)
  1469.         if ((cw += get_scaled_width (c)) > col_off)
  1470.           break;
  1471.       *cc = c;
  1472.       for (r = w->screen.lr; r <= w->screen.hr; ++r)
  1473.         if ((rh += get_scaled_height (r)) > row_off)
  1474.           break;
  1475.       *cr = r;
  1476.       return n;
  1477.     }
  1478.     }
  1479.   return MOUSE_ON_EDGE;
  1480. }
  1481.